package cn.zlj.pethome.user.service.impl;

import cn.zlj.pethome.basic.config.BussinessException;
import cn.zlj.pethome.basic.contant.BaseConstants;
import cn.zlj.pethome.basic.domain.Logininfo;
import cn.zlj.pethome.basic.jwt.JwtUtils;
import cn.zlj.pethome.basic.jwt.RsaUtils;
import cn.zlj.pethome.basic.jwt.UserInfo;
import cn.zlj.pethome.basic.mapper.LogininfoMapper;
import cn.zlj.pethome.basic.util.AjaxResult;
import cn.zlj.pethome.basic.util.HttpUtil;
import cn.zlj.pethome.basic.util.MD5Utils;
import cn.zlj.pethome.basic.util.StrUtils;
import cn.zlj.pethome.system.domain.Menu;
import cn.zlj.pethome.system.mapper.MenuMapper;
import cn.zlj.pethome.system.mapper.PermissionMapper;
import cn.zlj.pethome.system.mapper.RoleMapper;
import cn.zlj.pethome.user.domain.User;
import cn.zlj.pethome.user.domain.Wxuser;
import cn.zlj.pethome.user.dto.AccountDto;
import cn.zlj.pethome.user.dto.PhoneRegisterDto;
import cn.zlj.pethome.user.dto.WechatLoginDto;
import cn.zlj.pethome.user.mapper.UserMapper;
import cn.zlj.pethome.user.mapper.WxuserMapper;
import cn.zlj.pethome.user.service.LoginService;
import com.alibaba.fastjson.JSONObject;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.tuple.Pair;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;

import java.security.PrivateKey;
import java.util.*;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

import static cn.zlj.pethome.basic.jwt.JwtUtils.generateTokenExpireInMinutes;

@Service
@Slf4j
public class LoginServiceImpl implements LoginService {
    @Autowired
    private RedisTemplate redisTemplate;

    @Autowired
    private LogininfoMapper logininfoMapper;

    @Autowired
    private WxuserMapper wxuserMapper;
    @Autowired
    private UserMapper userMapper;
    @Autowired
    private PermissionMapper permissionMapper;
    @Autowired
    private MenuMapper menuMapper;


    @Override
    public Map<String, Object> accountLogin(AccountDto accountDto) {
        //判断非空
        //判断用户名是否存在
        Logininfo logininfo = logininfoMapper.findByUsername(accountDto.getUsername(), accountDto.getType());
        if(logininfo==null){
            throw new BussinessException("密码或账户错误");
        }
        //判断密码是否一致
        if(StringUtils.isBlank(logininfo.getPassword())){
            throw new BussinessException("密码或账户错误");
        }
        String pwd=logininfo.getSalt()+accountDto.getPassword();
        pwd= MD5Utils.encrypByMd5(pwd);
        if(!pwd.equals(logininfo.getPassword())){
            throw new BussinessException("密码或账户错误");
        }
        return    getMap(logininfo);
    }

//    private Map<String, Object> getMap(Logininfo logininfo) {
//        //放入token redis
//        String token= UUID.randomUUID().toString();
//        redisTemplate.opsForValue().set(token, logininfo,30, TimeUnit.MINUTES);
//        logininfo.setPassword("");
//        logininfo.setEmail("");
//        logininfo.setPhone("");
//        Map<String, Object> map = new HashMap<>();
//        map.put("token",token);
//        map.put("logininfo", logininfo);
//        return map;
//    }

private Map<String, Object> getMap(Logininfo logininfo) {
    //jwt方案
    PrivateKey privateKey = RsaUtils.getPrivateKey(JwtUtils.class.getClassLoader().getResource("jwt/pethome_auth_rsa.pri").getFile());
    UserInfo user=new UserInfo();
    user.setLogininfo(logininfo);
    Map<String, Object> map = new HashMap<>();
    //如果类型为0 需要加入权限
    if(logininfo.getType()==0){
        List<String> permissions = permissionMapper.findByLoginInfo(logininfo.getId());
        List<Menu> menus =menuMapper.findByLoginInfo(logininfo.getId());
        user.setMenus(menus);
        user.setPermissions(permissions);
        map.put("permissions", permissions);
        map.put("menus", menus);
    }
    String token = generateTokenExpireInMinutes(user, privateKey, 30);

    logininfo.setPassword("");
    logininfo.setEmail("");
    logininfo.setPhone("");
    map.put("token",token);
    map.put("logininfo",logininfo);
    return map;
}
    @Override
    public AjaxResult wechatLogin(WechatLoginDto wechatLoginDto) {
        //根据第二个接口获取code
        if(StringUtils.isBlank(wechatLoginDto.getCode())){
            throw new BussinessException("code为空");
        }
        //根据code获取token，openid
        String url=String.format(BaseConstants.WxLoginCons.WX_LOGIN_TOKEN_URL,BaseConstants.WxLoginCons.APPID
        ,BaseConstants.WxLoginCons.WX_LOGIN_SECRET,wechatLoginDto.getCode());
        String json = HttpUtil.httpGet(url);
        JSONObject jsonObject = JSONObject.parseObject(json);
        String openid = jsonObject.getString("openid");
        String accessToken = jsonObject.getString("access_token");
        Pair<String, Object> pair = Pair.of(accessToken,openid);
        //根据openid判断有wx_user没数据

        Wxuser wxuser = wxuserMapper.findByopenid((String) pair.getRight());
        if(wxuser!=null&&wxuser.getUserId()!=null){
            //登录过直接返回给前端token，和logininfo
            Logininfo logininfo = logininfoMapper.findByUserId(wxuser.getUserId());
            Map<String, Object> map = getStringObjectMap(logininfo);
            return AjaxResult.me().success(map);
        }
        // 当前人没有绑定
        StringBuffer sb = new StringBuffer()
                .append("?accessToken=")
                .append(pair.getLeft())
                .append("&openId=").append(pair.getRight());
        return AjaxResult.me().fail("nobinder").setResultObj(sb);
    }

    private Map<String, Object> getStringObjectMap(Logininfo logininfo) {
        Map<String, Object> map = new HashMap<>();
        String token= UUID.randomUUID().toString();
        redisTemplate.opsForValue().set(token, logininfo,30, TimeUnit.MINUTES);
        logininfo.setPassword("");
        logininfo.setEmail("");
        logininfo.setPhone("");
        map.put("token",token);
        map.put("logininfo", logininfo);
        return map;
    }
    @Override
    public Map<String,Object> binder(WechatLoginDto wechatLoginDto) {
        checkParam(wechatLoginDto);
        //根据token获取微信信息
        Wxuser wxuser = getWxuser(wechatLoginDto);
        //判断该手机号是否已经被绑定
        User user =userMapper.findByPhone(wechatLoginDto.getPhone());
        Logininfo logininfo = new Logininfo();
        if(user==null){
            //设置user值
            user=setUser(wechatLoginDto);
            //设置logininfo值
            logininfo = getLogininfo(user);
            //添加
            logininfoMapper.add(logininfo);
            user.setLogininfoId(logininfo.getId());
            userMapper.add(user);

        }else {
            logininfo = logininfoMapper.findByUserId(user.getId());
        }
        wxuser.setUserId(user.getId());
        wxuserMapper.add(wxuser);
        return getStringObjectMap(logininfo);
    }

    private Wxuser getWxuser(WechatLoginDto wechatLoginDto) {
        String url=String.format(BaseConstants.WxLoginCons.WX_LOGIN_USER_INFO, wechatLoginDto.getAccessToken(), wechatLoginDto.getOpenId());
        String json = HttpUtil.httpGet(url);
        // json字符串转成 我们的实体
        Wxuser wxuser = JSONObject.parseObject(json, Wxuser.class);
        return wxuser;
    }

    private void checkParam(WechatLoginDto wechatLoginDto) {
        //非空判断
        if(StringUtils.isBlank(wechatLoginDto.getPhone())||StringUtils.isBlank(wechatLoginDto.getAccessToken())||StringUtils.isBlank(wechatLoginDto.getVerifyCode())){
            throw new BussinessException("绑定异常");
        }
        //判断验证码是否一致
        String yzm =(String) redisTemplate.opsForValue().get(String.format(BaseConstants.VerifyCodeConstants.BUSINESS_BINDER_PREFIX, wechatLoginDto.getPhone()));
        if(StringUtils.isBlank(yzm)){
            throw new BussinessException("验证码错误");
        }
        String [] msgCode=yzm.split(":");
        if(!msgCode[0].equals(wechatLoginDto.getVerifyCode())){
            throw new BussinessException("验证码错误");
        }
    }

    private Logininfo getLogininfo(User user) {
        Logininfo logininfo;
        logininfo=new Logininfo();
        BeanUtils.copyProperties(user,logininfo);
        return logininfo;
    }

    //设置user
    private User setUser(WechatLoginDto t){
        String salt=StrUtils.getRandomString(32);
        String pwd=salt+1;
        pwd= MD5Utils.encrypByMd5(pwd);
        return User
                .builder()
                .username(t.getPhone())
                .phone(t.getPhone())
                .state(1)
                .password(pwd)
                .salt(salt)
                .createtime(new Date())
                .build()
                ;

    }
}
